package org.yzh.scheduler.schedule;

import org.quartz.*;
import org.quartz.Trigger.TriggerState;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.yzh.scheduler.model.vo.JobInfo;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import static org.quartz.JobKey.jobKey;
import static org.quartz.TriggerKey.triggerKey;

@Component
public class SchedulerManager {

    private final Logger log = LoggerFactory.getLogger(SchedulerManager.class);

    private final Scheduler scheduler;

    public SchedulerManager(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    public List<JobInfo> getAllJob() throws SchedulerException {
        List<String> groupNames = scheduler.getJobGroupNames();
        List<JobInfo> jobs = new ArrayList<>(groupNames.size());

        for (String group : groupNames) {

            for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.groupEquals(group))) {
                JobInfo job = new JobInfo(jobKey.getName(), jobKey.getGroup());

                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                if (!triggers.isEmpty()) {

                    Trigger trigger = triggers.get(0);
                    job.setState(scheduler.getTriggerState(trigger.getKey()));

                    if (trigger instanceof CronTrigger) {
                        String cronExpression = ((CronTrigger) trigger).getCronExpression();
                        job.setCronExpression(cronExpression);
                    }
                }
                jobs.add(job);
            }
        }
        return jobs;
    }

    public List<JobInfo> getRunningJob() throws SchedulerException {
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        List<JobInfo> jobs = new ArrayList<>(executingJobs.size());

        for (JobExecutionContext executingJob : executingJobs) {
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            JobInfo job = new JobInfo(jobKey.getName(), jobKey.getGroup());

            Trigger trigger = executingJob.getTrigger();
            job.setState(scheduler.getTriggerState(trigger.getKey()));

            if (trigger instanceof CronTrigger) {
                String cronExpression = ((CronTrigger) trigger).getCronExpression();
                job.setCronExpression(cronExpression);
            }
            jobs.add(job);
        }
        return jobs;
    }

    public void createJob(String name, String group, String cronExpression) throws SchedulerException {
        TriggerKey triggerKey = triggerKey(name, group);
        if (scheduler.checkExists(triggerKey))
            return;

        Class<? extends Job> jobClass = RemoteHttpJobBean.class;

        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey(name, group)).build();

//        withMisfireHandlingInstructionDoNothing：不触发立即执行，等待下次调度；
//        withMisfireHandlingInstructionIgnoreMisfires：以错过的第一个频率时间立刻开始执行；
//        withMisfireHandlingInstructionFireAndProceed：以当前时间为触发频率立刻触发一次执行；
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

        scheduler.scheduleJob(jobDetail, trigger);
    }

    public void updateCron(String name, String group, String cronExpression) throws SchedulerException {
        TriggerKey triggerKey = triggerKey(name, group);
        if (!scheduler.checkExists(triggerKey))
            return;

        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        if (trigger != null) {

            if (trigger.getCronExpression().equals(cronExpression))
                return;

            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            scheduler.rescheduleJob(triggerKey, trigger);
        } else {

            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            JobDetail jobDetail = scheduler.getJobDetail(jobKey(name, group));

            Set<Trigger> triggerSet = new TreeSet<>();
            triggerSet.add(trigger);

            scheduler.scheduleJob(jobDetail, triggerSet, true);
        }
    }

    public boolean delete(String name, String group) throws SchedulerException {
        return scheduler.deleteJob(jobKey(name, group));
    }

    public void runOnce(String name, String group) throws SchedulerException {
        scheduler.triggerJob(jobKey(name, group));
    }

    public void pauseJob(String name, String group) throws SchedulerException {
        scheduler.pauseJob(jobKey(name, group));
    }

    public void resumeJob(String name, String group) throws SchedulerException {
        scheduler.resumeJob(jobKey(name, group));
    }

    public TriggerState getTriggerState(String name, String group) throws SchedulerException {
        return scheduler.getTriggerState(triggerKey(name, group));
    }

    public boolean checkExists(String name, String group) throws SchedulerException {
        return scheduler.checkExists(triggerKey(name, group));
    }
}